home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-05-29 | 8.4 KB | 298 lines | [TEXT/ALFA] |
- // This may look like C code, but it is really -*- C++ -*-
- /*
- ************************************************************************
- *
- * Modified File class
- * to read integers of various sizes taking the byte order
- * into account
- * and bit-stream IO
- *
- * $Id: endian_io.cc,v 2.1 1995/03/02 18:06:20 oleg Exp oleg $
- *
- ************************************************************************
- */
-
- #ifdef __GNUC__
- #pragma implementation
- #endif
-
- #include "endian_io.h"
- #include "std.h"
-
- /*
- *------------------------------------------------------------------------
- * Error handling
- */
-
- void EndianIOData::error(const char *descr)
- {
- if( eof() )
- _error("'%s' failed because of the End-Of-File",descr);
- perror(descr);
- _error("Aborted due to the I/O error above");
- }
-
- void EndianIOData::assert_open(const char * file_name)
- {
- if( good() )
- return;
- perror("Opening error");
- _error("Failed to open file '%s' because of the error above",file_name);
- }
-
- /*
- *------------------------------------------------------------------------
- * Opening/closing
- *
- * Note that when the EndianIO stream is shared, it shares also the i/o
- * buffer with the existing stream. Care should be taken
- * to not destroy the buffer when the attached stream is closed/destroyed.
- * The situation is similar to what happens when a file handle is
- * duplicated with the system function dup(). Note that creating a new
- * file buffer for the attached stream based on the dup()-ed file
- * handle is not enough. Indeed, the old (sample) stream could've read
- * some data ahead in its buffer, so the system file pointer would not
- * correspond to data that were actually read (and consumed) by the
- * user. This situation can be partly remedied using a fstream::sync()
- * function (which sets the system file pointer to correspond to what
- * actually was read from the stream and discards the read-ahead data).
- * However, when the attached stream reads from the file and advances the file
- * pointer, the user of the original stream should be able to recognize
- * the fact that the file was read by another stream. This problem cannot
- * be solved withoud sharing the file buffer itself.
- */
-
- void EndianIOData::share_with(EndianIOData& a_file)
- {
- #if 0 // Because of the stupid implementation of filebuf:
- if( rdbuf() ) // filebuf is a part of the class fstream in GCC
- delete rdbuf(); // Destroy the old stream buffer
- #endif
- init(a_file.rdbuf()); // Share the buffer of a_file
- byte_order = a_file.byte_order;
- shared = true;
- clear();
- }
-
-
- // leave the stream open when it was attached
- void EndianIn::close(void)
- {
- if( !was_shared() )
- ifstream::close();
- }
-
- void EndianOut::close(void)
- {
- if( !was_shared() )
- ofstream::close();
- }
- // If the stream was attached, detach it
- // from the buffer
- EndianIOData::~EndianIOData(void)
- {
- if( was_shared() )
- init(0), shared=false;
- }
-
- /*
- *------------------------------------------------------------------------
- * Reading routines
- */
-
- // Read a SHORT (2 bytes) datum item
- // in the specified byte_order
- unsigned short int EndianIn::read_short(const char * op_description)
- {
- unsigned char c1, c2;
-
- if( !get(c1) || !get(c2) ) // Read 2 consecutive bytes
- error(op_description);
-
- if( q_MSBfirst() )
- return (c1 << 8) | c2;
- else
- return (c2 << 8) | c1;
- }
-
- // Read a LONG (4 bytes) datum item
- // in the specified byte_order
- unsigned long int EndianIn::read_long(const char * op_description)
- {
- unsigned char c1, c2, c3, c4;
-
- if( !get(c1) || !get(c2) || // Read 4 consecutive bytes
- !get(c3) || !get(c4) )
- error(op_description);
-
- if ( q_MSBfirst() )
- return (c1 << 24) | (c2 << 16) | (c3 << 8) | c4;
- else
- return (c4 << 24) | (c3 << 16) | (c2 << 8) | c1;
- }
-
-
- /*
- *------------------------------------------------------------------------
- * Service writing routines
- */
-
- void EndianOut::write_byte
- (const int item, const char * op_description)
- {
- if( !put(item) )
- error(op_description);
- }
-
- // Write out a short item as specified by
- // the byte_order
- void EndianOut::write_short
- (const unsigned short item, const char * op_description)
- {
- #if 0 // The following does NOT work
- union { // because it doesn't make sure
- unsigned short int short_int; // that c2 follows c1
- struct { unsigned char c1,c2; } bytes;
- } int_bytes;
- int_bytes.short_int = item;
- write_byte(int_bytes.bytes.c2,"write_short, 2nd byte");
- write_byte(int_bytes.bytes.c1,"write_short, 1st byte");
- #endif
- if( q_MSBfirst() )
- write_byte((item>>8) & 0xff,"write_short, hi byte"),
- write_byte(item & 0xff,"write_short, lo byte");
- else
- write_byte(item & 0xff,"write_short, lo byte"),
- write_byte((item>>8) & 0xff,"write_short, hi byte");
- }
-
-
- // Write out a long item as specified by
- // the byte_order
- void EndianOut::write_long
- (const unsigned long item, const char * op_description)
- {
- register unsigned int t = item;
- register int i;
-
- if( q_MSBfirst() )
- for(i=24; i>=0; i-=8)
- write_byte((t >> i) & 0xff,"write_long");
- else
- for(i=0; i<4; i++)
- write_byte(t & 0xff,"write_long"), t >>= 8;
- }
-
- /*
- *------------------------------------------------------------------------
- * Reading/Writing signed short (16-bit) integers
- * using variable-size code
- * The code is intended for writing a collection of short integers where many
- * of them are rather small in value; still, big values can crop up at times,
- * so we can't limit the size of the code to anything less than 16 bits.
- * The code is a variation of a start-stop code described in Appendix A,
- * "Variable-length representations of the integers" of the "Text Compression"
- * book by T.Bell, J.Cleary and I.Witten, p.290-295. The present code
- * features support for both negative and positive numbers and optimization
- * using a fact that all numbers are no larger than 2^15-1 in abs value
- * and assumption that most of them smaller than 512 (in absolute value)
- *
- * Specifically, the code is as follows:
- * For numbers not exceeding 63 in abs value, the code is
- * 0 sign-bit 6-bits-of-abs-value (most significant bit first)
- * For numbers within the range [64,511+64] in abs value, the code is
- * 10 sign-bit 9-bits-of-(abs-value - 64)
- * For numbers within the range [64+512,4095+512+64] in abs value, the code is
- * 110 sign-bit 12-bits-of-(abs-value - 576)
- * For bigger numbers, the code is
- * 111 16-bits-of-value
- * Thus the penalty is at most 3 extra bits (comparing with the plain 16-bit
- * encoding) for *very* big numbers.
- */
-
- // Write a signed short integer
- // using a variable size code
- void BitOut::put_short(short item)
- {
- int abs_val = abs(item);
- if( !(abs_val & ~63) ) // small number
- {
- put_bit(0);
- put_bit(item < 0);
- for(register int i=32; i!=0; i>>=1)
- put_bit(abs_val & i ? 1 : 0); // write 6 bits with MSB first
- return;
- }
-
- if( !((abs_val-=64) & ~511) )
- {
- put_bit(1);
- put_bit(0);
- put_bit(item < 0);
- for(register int i=256; i!=0; i>>=1)
- put_bit(abs_val & i ? 1 : 0);
- return;
- }
-
- if( !((abs_val-=512) & ~4095) )
- {
- put_bit(1);
- put_bit(1);
- put_bit(0);
- put_bit(item < 0);
- for(register int i=2048; i!=0; i>>=1)
- put_bit(abs_val & i ? 1 : 0);
- return;
- }
-
- put_bit(1); // Very big number: default case
- put_bit(1);
- put_bit(1); // Write all 16 bits with MSB first
- for(register unsigned int i=(1<<15); i!=0; i>>=1)
- put_bit(item & i ? 1 : 0);
-
- }
-
- // Get a short integer that was written
- // using a variable size code
- short BitIn::get_short(void)
- {
-
- if( !get_bit() ) // If the first bit turns out zero
- {
- const bool neg_sign = get_bit();
- int val = 0;
- for(register int i=32; i!=0; i>>=1) // Read 6 bits of abs value
- if( get_bit() ) // (MSB first)
- val |= i;
- return neg_sign ? -val : val;
- }
-
- if( !get_bit() ) // First bit was 1, second is 0
- {
- const bool neg_sign = get_bit();
- int val = 0;
- for(register int i=256; i!=0; i>>=1)
- if( get_bit() )
- val |= i;
- return val += 64, neg_sign ? -val : val;
- }
-
- if( !get_bit() ) // First two bits were 1, third is 0
- {
- const bool neg_sign = get_bit();
- int val = 0;
- for(register int i=2048; i!=0; i>>=1)
- if( get_bit() )
- val |= i;
- return val += 64+512, neg_sign ? -val : val;
- }
-
- int val = 0; // First three bits were all ones
- for(register unsigned int i=(1<<15); i!=0; i>>=1)
- if( get_bit() )
- val |= i;
- return val;
- }
-
-